//kZime
# include <bits/stdc++.h>
# define MAXN 10010
using namespace std;
inline double gd() {
	char a[100];
	a[0] = getchar();
	int len = 0;
	for(; !isdigit(a[len]); a[len] = getchar()) if (a[len] == '-') len++;
	for(; isdigit(a[len]) || a[len] == '.' ;a[len] = getchar()) len++;
	return atof(a);
}
class POINT{
public:
	double x,y;
};
POINT operator - (POINT a,POINT b){
	return (POINT){a.x-b.x,a.y-b.y};
}
bool operator < (POINT a,POINT b){
	if(a.y<b.y) return true;
	if(a.y>b.y) return false;
	if(a.x<b.x) return true;
	return false;
}
double dist(POINT a,POINT b){
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double crp(POINT a,POINT b){
	return a.x*b.y-b.x*a.y;
}
void swap(POINT &a,POINT &b){
	POINT c;
	c=a,a=b,b=c;
}
POINT p[MAXN];
int n;
deque<POINT> convexhull;
bool cmp(POINT a,POINT b){
	return crp(a-p[1],b-p[1])>0;
}
bool anticlock(POINT x,POINT a,POINT b){
	return crp(a-x,b-x)>0;
}
void Graham(void){
	sort(p+2,p+1+n,cmp);
	int i;
	convexhull.push_back(p[1]),convexhull.push_back(p[2]);
	int last;
	for(i=3;i<=n;i++){
		last=convexhull.size()-1;
		while(!anticlock(convexhull[last],p[i],convexhull[last-1])){
			convexhull.pop_back();
			last--;
		}
		convexhull.push_back(p[i]);
	}
}
void answer(void){
	double sum=0;
	int i;
	for(i=1;i<convexhull.size();i++) sum+=dist(convexhull[i-1],convexhull[i]);
	sum+=dist(convexhull[0],convexhull[convexhull.size()-1]);
	printf("%.2lf\n",sum);
}
void init(void){
	int minpoint=1;
	int i;
	for(i=2;i<=n;i++) if(p[i]<p[minpoint]) minpoint=i;
	swap(p[1],p[minpoint]);
}
void read(void){
	scanf("%d",&n);
	int i;
	for(i=1;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y);
}
int main(){
	freopen("fc.in", "r", stdin);
	freopen("fc.out", "w", stdout);
	read();
	init();
	Graham();
	answer();
	return 0;
}
 
/*
 * -----------------------
 *  yangli:
 *  4
 *  1 0
 *  -1 0
 *  1 0
 *  3 3
 *  -----------------------
 *  test:
 *  5.00
 *  -----------------------
 *  right:
 *  10.61
 *  -----------------------
*/

